package cn.zz.veggie.persistence.repository;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.springframework.stereotype.Repository;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.zz.comm.core.types.query.PageQuery;
import cn.zz.comm.exception.classes.FatalErrorException;
import cn.zz.comm.util.CollectorUtil;
import cn.zz.comm.util.DateTimeUtil;
import cn.zz.veggie.model.domain.Quote;
import cn.zz.veggie.model.query.QuoteQuery;
import cn.zz.veggie.persistence.dao.UserQuoteDao;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 用户报价(QuoteUser)repo
 *
 * @author zhongq
 * @since 2024-05-22 20:16:42
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class QuoteRepository {

	private final UserQuoteDao userQuoteDao;

	public Quote findById(Integer id) {
		Objects.requireNonNull(id);
		final QuoteQuery query = new QuoteQuery();
		query.setId(id);
		return userQuoteDao.selectOne(query);
	}

	public Map<Integer, Quote> findByIds(Collection<Integer> ids) {
		if (CollectionUtil.isEmpty(ids)) {
			return Collections.emptyMap();
		}
		final QuoteQuery query = new QuoteQuery();
		query.setIds(ids);
		query.page(PageQuery.size(ids.size()));
		final List<Quote> records = userQuoteDao.select(query);
		return CollectorUtil.btmByKeyFun(records, Quote::getId);
	}

	public List<Quote> findByPage(QuoteQuery query, PageQuery page) {
		query.page(page);
		page.setTotal(userQuoteDao.selectCount(query));
		if (page.hasMoreItems()) {
			return userQuoteDao.select(query);
		}
		return Collections.emptyList();
	}

	public void save(Quote quote) {
		Objects.requireNonNull(quote);
		if (quote.getId() == null) {
			// insert
			final int effect = userQuoteDao.insert(quote);
			if (effect != 1) {
				throw new FatalErrorException("created quoteUser fail ");
			}
			log.info("created quoteUser for {}", quote.getId());
		} else {
			// update
			final int effect = userQuoteDao.updateById(quote);
			if (effect != 1) {
				throw new FatalErrorException("update quoteUser fail ");
			}
			log.info("updated quoteUser for {}", quote.getId());
		}
	}

	public void deleteById(Integer id) {
		Objects.requireNonNull(id);
		final int effect = userQuoteDao.deleteById(id);
		if (effect != 1) {
			log.error("delete");
			throw new FatalErrorException("delete quoteUser fail ");
		}
		log.info("delete quoteUser for {}", id);
	}

	public void deleteByIds(Collection<Integer> ids) {
		if (CollUtil.isEmpty(ids)) {
			return;
		}
		final int effect = userQuoteDao.deleteByIds(ids);
		log.info("delete quoteUser for {}", effect);
	}

	public Quote findByUidAndPid(Integer uid, Integer pid) {
		Objects.requireNonNull(uid);
		Objects.requireNonNull(pid);
		final QuoteQuery query = new QuoteQuery();
		query.setUid(uid);
		query.setPid(pid);
		return userQuoteDao.selectOne(query);
	}

	public Map<Integer, Integer> findProductQuote(Integer uid, Collection<Integer> pids) {
		Objects.requireNonNull(uid);
		if (CollUtil.isEmpty(pids)) {
			return Collections.emptyMap();
		}
		final QuoteQuery query = new QuoteQuery();
		query.setUid(uid);
		query.setPids(pids);
		query.size = pids.size();
		final List<Quote> quotes = userQuoteDao.select(query);
		return CollectorUtil.btm(quotes, Quote::getPid, Quote::getPrice);
	}

	public void updateOrSaveQuotes(Integer uid, Map<Integer, Integer> currQuoteMap) {
		List<Quote> userQuotes = findUserQuotes(uid, currQuoteMap.keySet());
		Map<Integer, Quote> quoteMap = CollectorUtil.btmByKeyFun(userQuotes, Quote::getPid);
		final long currentTime = DateTimeUtil.unixTime();
		List<Quote> waitInsert = new ArrayList<>(currQuoteMap.size());
		List<Quote> waitUpdate = new ArrayList<>(currQuoteMap.size());

		currQuoteMap.forEach((productId, price) -> {
			final Quote dbQuote = quoteMap.get(productId);
			if (dbQuote != null && dbQuote.getPrice().equals(price)) {
				return;
			}
			Quote quote = new Quote();
			quote.setId(dbQuote == null ? null : dbQuote.getId());
			quote.setUid(uid);
			quote.setPid(productId);
			quote.setPrice(price);
			quote.setCreatedAt(currentTime);
			quote.setUpdatedAt( currentTime);
			(dbQuote == null ? waitInsert : waitUpdate).add(quote);
		});
		if (!waitInsert.isEmpty()) {
			userQuoteDao.insertBatch(waitInsert);
		}
		waitUpdate.forEach(userQuoteDao::updateById);
	}

	private List<Quote> findUserQuotes(Integer uid, Collection<Integer> pids) {
		Objects.requireNonNull(uid);
		if (CollUtil.isEmpty(pids)) {
			return Collections.emptyList();
		}
		final QuoteQuery query = new QuoteQuery();
		query.setUid(uid);
		query.setPids(pids);
		query.size = pids.size();
		return userQuoteDao.select(query);
	}
}